package edu.del.teamknowledgebase.service.auth.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import edu.del.teamknowledgebase.common.constant.cache.CacheKeyConstant;
import edu.del.teamknowledgebase.common.exception.BusinessException;
import edu.del.teamknowledgebase.common.result.BusinessCode;
import edu.del.teamknowledgebase.vo.CaptchaVO;
import edu.del.teamknowledgebase.service.auth.CaptchaService;
import io.micrometer.common.util.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 验证码服务实现类
 * @author: Del
 * @date: 2025/10/16 19:27
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CaptchaServiceImpl implements CaptchaService {

    private final StringRedisTemplate redisTemplate;

    /**
     * 验证码过期时间（分钟）
     */
    private static final long CAPTCHA_EXPIRE_MINUTES = 5;

    /**
     * 验证码图片宽度
     */
    private static final int CAPTCHA_WIDTH = 120;

    /**
     * 验证码图片高度
     */
    private static final int CAPTCHA_HEIGHT = 40;

    /**
     * 验证码长度
     */
    private static final int CAPTCHA_CODE_LENGTH = 4;

    /**
     * 验证码干扰线数量
     */
    private static final int CAPTCHA_LINE_COUNT = 5;


    @Override
    public CaptchaVO generateCaptcha() {
        // 生成线性验证码
        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(
            CAPTCHA_WIDTH,
            CAPTCHA_HEIGHT,
            CAPTCHA_CODE_LENGTH,
            CAPTCHA_LINE_COUNT
        );

        // 获取验证码文本
        String  captchaCode = captcha.getCode();

        // 生成唯一的验证码 Key
        String captchaKey = UUID.randomUUID().toString();

        // 将验证码存入 Redis 并且设置过期时间
        String redisKey = String.format(CacheKeyConstant.CAPTCHA_KEY_PREFIX, captchaKey);
        redisTemplate.opsForValue().set(
                redisKey,
                // 转小写存储，验证时不区分大小写
                captchaCode.toLowerCase(),
                CAPTCHA_EXPIRE_MINUTES,
                TimeUnit.MINUTES
        );

        // 获取 Base64 编码图片
        String captchaImage = captcha.getImageBase64();

        log.info("生成验证码：key = {}，code = {}", captchaKey, captchaCode);

        return CaptchaVO
                .builder()
                .captchaImage(captchaImage)
                .captchaKey(captchaKey).build();
    }

    @Override
    public boolean verifyCaptcha(String captchaKey, String captchaCode) {
        // 参数校验
        if (StringUtils.isBlank(captchaKey) || StringUtils.isBlank(captchaCode)) {
            throw new BusinessException(BusinessCode.PARAM_VALID_ERROR, "验证码 key 或验证码不能为空");
        }

        // 获取 Redis 验证码
        String redisKey = String.format(CacheKeyConstant.CAPTCHA_KEY_PREFIX, captchaKey);
        String storedCode = redisTemplate.opsForValue().get(redisKey);

        if (storedCode == null) {
            throw new BusinessException(BusinessCode.CAPTCHA_EXPIRED, "验证码已过期");
        }

        // 不区分大小写比较
        boolean isValid = storedCode.equalsIgnoreCase(captchaCode);

        if (isValid) {
            log.info("验证码验证成功: key={}", captchaKey);
            // 验证成功后立即删除，防止重复使用
            removeCaptcha(captchaKey);
        } else {
            log.warn("验证码验证失败: key={}, 输入={}, 正确={}", captchaKey, captchaCode, storedCode);
            throw new BusinessException(BusinessCode.CAPTCHA_ERROR, "您输入的验证码不正确，请重新输入");
        }

        return true;
    }

    @Override
    public void removeCaptcha(String captchaKey) {
        if (captchaKey != null) {
            String redisKey = String.format(CacheKeyConstant.CAPTCHA_KEY_PREFIX, captchaKey);
            redisTemplate.delete(redisKey);
            log.info("删除验证码: key={}", captchaKey);
        }
    }
}
